package com.pingan.haofang.searchcloud.web.index.controller;

import com.pingan.haofang.framework.common.functional.lang.control.bean.BeanCopy;
import com.pingan.haofang.searchcloud.api.constants.EngineType;
import com.pingan.haofang.searchcloud.api.matedata.IndexMeta;
import com.pingan.haofang.searchcloud.api.matedata.IndexMetadataHolderFactory;
import com.pingan.haofang.searchcloud.common.configuration.ClusterProperties;
import com.pingan.haofang.searchcloud.common.constants.WebConstants;
import com.pingan.haofang.searchcloud.common.dto.OperationResult;
import com.pingan.haofang.searchcloud.common.dto.PageDTO;
import com.pingan.haofang.searchcloud.common.validator.annotation.Valid;
import com.pingan.haofang.searchcloud.index.dto.IndexDTO;
import com.pingan.haofang.searchcloud.index.dto.IndexInfoDTO;
import com.pingan.haofang.searchcloud.index.dto.IndexInfoQueryResult;
import com.pingan.haofang.searchcloud.index.dto.IndexQueryDTO;
import com.pingan.haofang.searchcloud.index.dto.IndexQueryResult;
import com.pingan.haofang.searchcloud.index.service.ClusterService;
import com.pingan.haofang.searchcloud.index.service.IndexService;
import com.pingan.haofang.searchcloud.metadata.dto.MetadataFieldDTO;
import com.pingan.haofang.searchcloud.quartz.dto.TaskQueryDto;
import com.pingan.haofang.searchcloud.quartz.service.IndexBuildScheduleTaskService;
import com.pingan.haofang.searchcloud.register.metadata.DBIndexMetadataRegister;
import com.pingan.haofang.searchcloud.register.metadata.IndexMetaTransfer;
import com.pingan.haofang.searchcloud.web.index.form.IndexIdForm;
import com.pingan.haofang.searchcloud.web.index.form.IndexInfoForm;
import com.pingan.haofang.searchcloud.web.index.form.IndexQueryForm;
import com.pingan.haofang.searchcloud.web.index.validator.IndexValidator;
import com.pingan.haofang.searchcloud.web.index.vo.ClusterVo;
import com.pingan.haofang.searchcloud.web.index.vo.EngineVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 索引管理相关
 *
 * @author baojie371
 * @date 17/5/3
 * @since 1.0.0
 */
@RestController
@RequestMapping(WebConstants.WEB_PREFIX + "/index")
@Api(tags = "Index.Manage", description = "索引管理接口")
public class IndexController {

    protected static Logger LOG = LoggerFactory.getLogger(IndexController.class);

    @Autowired
    private IndexService indexService;

    @Autowired
    private ClusterService clusterService;

    @Autowired
    private DBIndexMetadataRegister dBIndexMetadataRegister;

    @Autowired
    private IndexBuildScheduleTaskService indexBuildScheduleTaskService;


    /**
     * 索引查询
     *
     * @param form
     * @return
     */
    @RequestMapping(value = "", method = RequestMethod.GET)
    @Valid
    @ApiOperation("索引查询")
    public PageDTO<IndexQueryResult> query(@ModelAttribute IndexQueryForm form) {

        IndexQueryDTO queryDTO = BeanCopy.toFunction(IndexQueryDTO.class, BeanUtils::copyProperties).apply(form);
        return indexService.query(queryDTO);
    }

    /**
     * 索引信息查询
     *
     * @param id
     * @return
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    @ApiOperation("索引信息查询")
    public IndexInfoQueryResult queryById(@PathVariable(name = "id") long id) {
        return indexService.queryById(id);
    }

    /**
     * 索引基本信息查询
     *
     * @param id
     * @return
     */
    @RequestMapping(value = "/basicInfo/{id}", method = RequestMethod.GET)
    @ApiOperation("索引基本信息查询")
    public IndexQueryResult queryBasicInfoById(@PathVariable(name = "id") long id) {
        return indexService.queryBasicInfoById(id);
    }

    /**
     * 保存索引
     *
     * @param form
     */
    @RequestMapping(value = "", method = RequestMethod.POST)
    @Valid(IndexValidator.class)
    @ApiOperation("保存索引")
    public void save(@RequestBody IndexInfoForm form) throws SchedulerException {

        IndexInfoDTO indexInfoDTO = BeanCopy
                .of(form, new IndexInfoDTO()).set(dto -> dto.setBasicInfo(new IndexDTO()))
                .copy((f, dto) -> BeanUtils.copyProperties(f.getBasicInfo(), dto.getBasicInfo()))
                .copy((f, dto) -> dto.setFields(f.getFields().stream().map(BeanCopy.toFunction(MetadataFieldDTO.class,
                        BeanUtils::copyProperties)).collect(Collectors.toList())))
                .get();
        indexService.save(indexInfoDTO);

    }

    /**
     * 启用索引
     *
     * @param form
     */
    @RequestMapping(value = "/enableIndex/{indexId}", method = RequestMethod.PUT)
    @ApiOperation("启用索引")
    @Valid
    public OperationResult enableIndex(@ModelAttribute IndexIdForm form) throws SchedulerException {
        OperationResult result = indexService.enableIndex(form.getIndexId(), false);
        indexBuildScheduleTaskService.refresh(form.getIndexId());
        return result;

    }

    /**
     * @Scheduled 定时任务执行，注意不要删除
     */
    @RequestMapping(value = "/enableIndex/all", method = RequestMethod.PUT)
    @Scheduled(fixedRate = 1000 * 60 * 10)
    public void enableAllIndex() {
        List<IndexQueryResult> result = indexService.queryAllIndexOfStorage(new TaskQueryDto());
        for (IndexQueryResult index : result) {
            try {
                IndexInfoQueryResult indexInfo = indexService.queryByIndexNameOfStorage(index.getIndexName());
                IndexMeta indexMeta = IndexMetaTransfer.indexInfo2IndexMeta(indexInfo);
                IndexMetadataHolderFactory.get().register(indexMeta);
            } catch (Exception e) {
                LOG.error("enableIndex all has error:", e);
            }
        }
    }


    /**
     * 清理Top数据的服务
     */
    @RequestMapping(value = "/clearstopcollection/{topnum}", method = RequestMethod.PUT)
    public void clearTopNStopCollection(@PathVariable(name = "topnum") int topnum) {
        List<IndexQueryResult> result = indexService.queryAllIndexOfStorage(new TaskQueryDto());
        for (IndexQueryResult index : result) {
            try {
                dBIndexMetadataRegister.clearOldConfigAndCollection(index.getIndexName(), topnum);
            } catch (Exception e) {
                LOG.error("dBIndexMetadataRegister clearOldConfigAndCollection has error:", e);
            }
        }
    }

    /**
     * 集群信息
     *
     * @return
     */
    @ApiOperation("集群信息")
    @RequestMapping(value = "/clusters", method = RequestMethod.GET)
    public List<EngineVo> getClusters() {
        Map<EngineType, List<ClusterProperties.ClusterInfo>> map = clusterService.getClusterInfo();

        List<EngineVo> result = new ArrayList<>();
        for (Map.Entry<EngineType, List<ClusterProperties.ClusterInfo>> entry : map.entrySet()) {
            List<ClusterVo> clusters = new ArrayList<>();
            for (ClusterProperties.ClusterInfo clusterInfo : entry.getValue()) {
                clusters.add(new ClusterVo(clusterInfo.getName(),
                        clusterInfo.getDescription(),
                        clusterInfo.isDisableCreate()));
            }
            result.add(new EngineVo(entry.getKey(), clusters));
        }
        return result;
    }

    @ApiOperation("索引增量初始化")
    @GetMapping("/schedule/incInit")
    public void incScheduleInit() throws SchedulerException {
        indexBuildScheduleTaskService.incScheduleInit();
    }

    @ApiOperation("索引增量暂停")
    @GetMapping("/schedule/incPause/{indexId}")
    public void incSchedulePause(@PathVariable("indexId") long indexId) throws SchedulerException {
        indexBuildScheduleTaskService.incSchedulePause(indexId);
    }

    @ApiOperation("索引增量恢复")
    @GetMapping("/schedule/incResume/{indexId}")
    public void incScheduleResume(@PathVariable("indexId") long indexId) throws SchedulerException {
        indexBuildScheduleTaskService.incScheduleResume(indexId);
    }

    @ApiOperation("索引增量刷新")
    @GetMapping("/schedule/incRefresh/{indexId}")
    public void incScheduleRefresh(@PathVariable("indexId") long indexId) throws SchedulerException {
        indexBuildScheduleTaskService.incScheduleRefresh(indexId);
    }

}
